package jp.gr.java_conf.mahny.security;

import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import jp.gr.java_conf.mahny.util.ByteUtils;

/**
 * 各種ハッシュを生成するためのユーティリティ
 * 
 * @author mahny
 * 
 */
public class HashUtils {
	/**
	 * ハッシュを生成する
	 * 
	 * @param org
	 *            ハッシュ元バイトデータ
	 * @param algorithm
	 *            アルゴリズム
	 * @return 生成したハッシュデータ
	 */
	public static byte[] getHash(byte[] org, HashAlgorithm algorithm) {

		// 引数・アルゴリズム指定が無い場合は計算しない
		if ((org == null) || (algorithm == null)) {
			return null;
		}

		// 初期化
		MessageDigest md = null;
		try {
			md = MessageDigest.getInstance(algorithm.getAlgorithm());
		} catch (NoSuchAlgorithmException e) {
			return null;
		}

		md.reset();
		md.update(org);
		return md.digest();
	}

	/**
	 * ハッシュを生成する
	 * 
	 * @param org
	 *            ハッシュ元文字列
	 * @param algorithm
	 *            アルゴリズム
	 * @return 生成したハッシュの文字列
	 */
	public static String getHashString(String org, HashAlgorithm algorithm) {

		// ハッシュを16進数文字列に変換
		byte[] hash = getHash(org.getBytes(), algorithm);
		if (hash == null) {
			return null;
		}

		StringBuffer sb = new StringBuffer();
		int cnt = hash.length;
		for (int i = 0; i < cnt; i++) {
			sb.append(Integer.toHexString((hash[i] >> 4) & 0x0F));
			sb.append(Integer.toHexString(hash[i] & 0x0F));
		}
		return sb.toString();
	}

	/**
	 * ハッシュ認証メッセージを生成する
	 * 
	 * @param org
	 *            ハッシュ元データ
	 * @param key
	 *            鍵
	 * @param algorithm
	 *            アルゴリズム
	 * @return 生成したハッシュデータ
	 */
	public static byte[] getKeyedHash(byte[] org, byte[] key,
			KeyedHashAlgorithm algorithm) {
		if ((ByteUtils.isEmpty(org)) || (ByteUtils.isEmpty(key))
				|| (algorithm == null)) {
			return null;
		}

		byte[] result = null;
		Key secret = null;
		Mac mac = null;
		try {
			secret = new SecretKeySpec(key, algorithm.getAlgorithm());
			mac = Mac.getInstance(secret.getAlgorithm());
			mac.init(secret);
			result = mac.doFinal(org);
		} catch (NoSuchAlgorithmException e) {
		} catch (InvalidKeyException e) {
		}
		return result;
	}
}
